package com.yungu.swift.report.utils;

import com.yungu.swift.base.model.admin.AdminReportParam;
import com.yungu.swift.utils.DateUtils;
import com.yungu.swift.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.*;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.List;

/**
 * Excel工具类
 *
 * @author XiuYin.Cui
 */
public class ExcelUtil {

    /**
     * 获取导出Excel工作薄
     *
     * @param list         数据源
     * @param clazz        类
     * @param templatePath 模板路径
     * @param duration     日期范围
     * @return
     * @throws Exception
     */
    public static XSSFWorkbook getExportWorkBook(List list, Class clazz, String templatePath, String duration) throws Exception {
        //获取导入模板
        InputStream in = ExcelUtil.class.getResourceAsStream(templatePath);
        XSSFWorkbook wb = new XSSFWorkbook(in);
        XSSFSheet sheet = wb.getSheetAt(0);
        //设置数据格式
        XSSFDataFormat dataFormat = wb.createDataFormat();
        //写入数据
        writeDate(duration, sheet, clazz, list, dataFormat);
        return wb;
    }

    /**
     * 写入数据
     *
     * @param duration   日期范围
     * @param sheet      表格
     * @param clazz      类
     * @param list       数据源
     * @param dataFormat
     * @throws Exception
     */
    public static void writeDate(String duration, XSSFSheet sheet, Class clazz, List list, XSSFDataFormat dataFormat) throws Exception {
        boolean isHasDuration = false;
        if (StringUtils.isNotEmpty("duration")) {//含有时间范围
            XSSFCell cell = sheet.getRow(1).getCell(0);//第二行，第二格
            String cellValue = cell.getStringCellValue();
            if (cellValue.trim().equals("duration")) {
                cell.setCellValue(duration);
                isHasDuration = true;
            }
        }
        int propertyRowNum = 2;
        if (isHasDuration) {
            propertyRowNum = 3;
        }
        XSSFRow propertyRow = sheet.getRow(propertyRowNum);//获取属性行
        int columnCount = propertyRow.getLastCellNum();//获取属性行的列数
        //循环赋值
        for (int i = 0; i < list.size(); i++) {
            Row dataRow = sheet.createRow(propertyRowNum + 1 + i);
            //循环为每列赋值
            for (int j = 0; j < columnCount; j++) {
                String propertyString = propertyRow.getCell(j).getStringCellValue();
                if (StringUtils.isEmpty(propertyString)) {
                    continue;
                }
                //使用反射
                Method getMethod = getGetMethod(clazz, propertyString);
                if (getMethod != null) {
                    Cell cell = dataRow.createCell(j);
                    XSSFCellStyle cellStyle = propertyRow.getCell(j).getCellStyle();
                    setCell(list.get(i), getMethod, cell, cellStyle, dataFormat);
                } else {
                    dataRow.createCell(j).setCellValue("");
                }
            }
        }
        if (propertyRowNum == sheet.getLastRowNum()) {
            sheet.removeRow(propertyRow);//没有数据，清空属性行
        } else {
            sheet.shiftRows(propertyRowNum + 1, sheet.getLastRowNum(), -1);//有数据，清空属性行，全部数据行上移一行（该函数从起始行，到结束行，上移一行）
        }
    }

    /**
     * 根据关键词查找对应的get方法
     *
     * @param objectClass
     * @param fieldName
     * @return
     */
    public static Method getGetMethod(Class objectClass, String fieldName) {
        StringBuffer sb = new StringBuffer();
        sb.append("get");
        sb.append(fieldName.substring(0, 1).toUpperCase());
        sb.append(fieldName.substring(1));
        try {
            return objectClass.getMethod(sb.toString());
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 设置单元格的值
     *
     * @param object
     * @param method
     * @param cell
     * @param cellStyle
     * @param dataFormat
     * @return
     * @throws Exception
     */
    private static Cell setCell(Object object, Method method, Cell cell, XSSFCellStyle cellStyle, XSSFDataFormat dataFormat) throws Exception {
        String returnType = method.getReturnType().getName();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/M/d");
        switch (returnType) {
            case "java.util.Date": {
                java.util.Date cellValue = (java.util.Date) method.invoke(object);
                if (cellValue != null) {
                    cell.setCellValue(sdf.format(cellValue));
                }
            }
            break;
            case "java.lang.Float": {
                Float cellValue = (java.lang.Float) method.invoke(object);
                if (cellValue != null) {
                    cellStyle.setDataFormat(dataFormat.getFormat("#,#0.00"));
                    cell.setCellStyle(cellStyle);
                    cell.setCellValue(Double.valueOf(cellValue.toString()));
                }
            }
            break;
            case "java.lang.Double": {
                Double cellValue = (java.lang.Double) method.invoke(object);
                if (cellValue != null) {
                    cellStyle.setDataFormat(dataFormat.getFormat("#,#0.00"));
                    cell.setCellStyle(cellStyle);
                    cell.setCellValue(cellValue);
                }
            }
            break;
            case "java.lang.String": {
                String cellValue = (java.lang.String) method.invoke(object);
                if (StringUtils.isNotEmpty(cellValue)) {
                    cell.setCellValue(cellValue);
                }
            }
            break;
            case "java.lang.Integer": {
                Integer cellValue = (java.lang.Integer) method.invoke(object);
                if (cellValue != null) {
                    cell.setCellValue(cellValue);
                }
            }
            break;
            case "java.math.BigDecimal": {
                java.math.BigDecimal cellValue = (java.math.BigDecimal) method.invoke(object);
                if (cellValue != null) {
                    cellStyle.setDataFormat(dataFormat.getFormat("#,#0.00"));
                    cell.setCellStyle(cellStyle);
                    cell.setCellValue(cellValue.doubleValue());
                }
            }
            break;
            default:
                break;
        }
        return cell;
    }

    /**
     * 下载
     *
     * @param reportParam
     * @param response
     * @param list
     * @param clazz
     * @param templatePath
     * @throws Exception
     */
    public static void download(AdminReportParam reportParam, HttpServletResponse response, List list, Class clazz, String templatePath) throws Exception {
        String templateName = templatePath.split("/")[2];
        String duration = "";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/M/d");

        if (reportParam.getStartTime() != null && reportParam.getEndTime() != null) {
            duration = simpleDateFormat.format(reportParam.getStartTime()) + "-" + simpleDateFormat.format(reportParam.getEndTime());
        }
        OutputStream os = response.getOutputStream();
        try {
            XSSFWorkbook workbook = ExcelUtil.getExportWorkBook(list, clazz, templatePath, duration);
            response.setHeader("Content-Disposition", "attachment; filename='" + templateName + "'");
            response.setContentType("application/vnd.ms-excel");
            workbook.write(os);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }

    /**
     * 下载
     *
     * @param reportParam
     * @param response
     * @param list
     * @param clazz
     * @param templatePath
     * @throws Exception
     */
    public static void download(AdminReportParam reportParam, HttpServletResponse response, List list, Class clazz, String templatePath, String description) throws Exception {
        String fileName = getFileName(reportParam, description);
        String duration = "";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/M/d");

        if (reportParam.getStartTime() != null && reportParam.getEndTime() != null) {
            duration = simpleDateFormat.format(reportParam.getStartTime()) + "-" + simpleDateFormat.format(reportParam.getEndTime());
        }
        OutputStream os = response.getOutputStream();
        try {
            XSSFWorkbook workbook = ExcelUtil.getExportWorkBook(list, clazz, templatePath, duration);
            response.setHeader("filename", URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            workbook.write(os);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }

    /**
     * 拼接导出文件名
     */
    public static String getFileName(AdminReportParam reportParam, String description) throws UnsupportedEncodingException {
        StringBuilder fileNamePart = new StringBuilder();
        fileNamePart.append(description);
        if (null != reportParam.getTypeModule() && reportParam.getTypeModule() != 0) {//有包含业务
            Integer typeModule = reportParam.getTypeModule();
            switch (typeModule) {
                case 1: {
                    fileNamePart.append("（出租车业务）_");
                }
                break;
                case 2: {
                    fileNamePart.append("（专车业务）_");
                }
                break;
                case 3: {
                    fileNamePart.append("（跨城拼车业务）_");
                }
                break;
                case 4: {
                    fileNamePart.append("（快车业务）_");
                }
                break;
                default:
                    break;
            }
        }
        if (reportParam.getStartTime() != null && reportParam.getEndTime() != null) {
            fileNamePart.append(DateUtils.format(reportParam.getStartTime(), "yyyyMMdd") + "-" + DateUtils.format(reportParam.getEndTime(), "yyyyMMdd"));
        }
        return fileNamePart.toString();
    }
}
